
//
// Created by 吴喆 on 2020/3/3.
//

#ifndef SUMMER_CAMERA_H
#define SUMMER_CAMERA_H

#include <glm/glm.hpp>
#include <glm/ext.hpp>
#include <iostream>
#include "Input.h"
#include "Time.h"

class GameObject;

enum class CameraMovement {
    FORWARD,
    BACKWARD,
    LEFT,
    RIGHT,
    VIEW_RIGHT,
    VIEW_LEFT,
    VIEW_UP,
    VIEW_DOWN,
    SPACE
};

// Default camera values
const float YAW = -90.0f;
const float PITCH = 0.0f;
const float SPEED = 0.5f;
const float SENSITIVITY = 0.1f;
const float ZOOM = 45.0f;


// An abstract camera class that processes input and calculates the corresponding Euler Angles, Vectors and Matrices for use in OpenGL
class Camera : public KeyboardObserver {
public:
    void onKeyboardInput(KeyEvent *event) override;


    void initTrackObject(GameObject *gameObject);

    /**
     * the {@code GameObject} which camera look at
     */
    GameObject *trackObject;
    glm::vec3 position;
    glm::vec3 Front;
    glm::vec3 Up;
    glm::vec3 Right;
    glm::vec3 WorldUp;
    // Euler Angles
    float Yaw;
    float Pitch;
    // Camera options
    float MovementSpeed;
    float MouseSensitivity;
    float Zoom;

    // Constructor with vectors
    Camera(float &maxSpeed, glm::vec3 position = glm::vec3(0.0f, 0.0f, 13.1211f),
           glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f),
           float yaw = YAW, float pitch = PITCH);

    void update();

    /**
     * the function of dist to speed
     * @param dist
     * @return speed
     */
    float distSpeedMapFunction(float dist);

    // Returns the view matrix calculated using Euler Angles and the LookAt Matrix
    virtual glm::mat4 getViewMatrix();

    virtual glm::mat4 getPerspectiveViewMatrix();

    virtual glm::mat4 getOthoProjectionMatrix();

    void processKeyboard(CameraMovement direction, float deltaTime);

    void processMouseMovement(float xoffset, float yoffset, bool constrainPitch = true);

    void ProcessMouseScroll(float yoffset);

private:
    double lastX = 0;
    double lastY = 0;
    /**
     * the distance between camera and {@code Scene}
     */
    double dist = 14.0;
    glm::vec3 currentCenter;
    glm::vec3 distCenter;

    float &maxSpeed;
    float currentSpeed;
    bool firstMouse = true;

    // Calculates the front vector from the Camera's (updated) Euler Angles
    void updateCameraVectors();
};

#endif //SUMMER_CAMERA_H
